<?php
namespace Home\Controller;
use Think\Controller;
class BaseController extends Controller {

    private $time;

    protected function getUserInfo()
    {
        //return array(); //是否屏蔽微信端打开限制

        $userInfo = session('userInfo');
        $scope = 'snsapi_userinfo';
        if(!empty($userInfo)){
            return $userInfo;
        }
        $code = I('get.code');
        if(!empty($code)){
            $webAccess = $this->getWebAccess($code);
            $userInfo = $this->getNewUserInfo($webAccess->access_token, $webAccess->openid);
            if(empty($userInfo->errcode))
            session('userInfo', $userInfo);
            return $userInfo;
        }
        $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
        $url = "$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
        //dump($redirect_uri);
        //exit;
        $this->getCode($url, $scope);
    }

    protected function getOpenid()
    {
        //return array(); //是否屏蔽微信端打开限制

        $openid = session('openid');
        $scope = 'snsapi_base';
        if(!empty($userInfo)){
            return $userInfo;
        }
        $code = I('get.code');
        if(!empty($code)){
            $webAccess = $this->getWebAccess($code);
            if(empty($webAccess->errcode))
            $openid = $webAccess->openid;
            session('openid', $openid);
            return $openid;
        }
        $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
        $url = "$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
        //dump($redirect_uri);
        //exit;
        $this->getCode($url, $scope);
    }

    private function getNewUserInfo($accessToken,$openid)
    {
        $url="https://api.weixin.qq.com/sns/userinfo?access_token=".$accessToken."&openid=".$openid."&lang=zh_CN";
        $result = json_decode(curl_get_contents($url));
        return $result;
    }

    protected function getSignPackage() {
        $jsapiTicket = $this->getJsApiTicket();

        // 注意 URL 一定要动态获取，不能 hardcode.
        $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
        $url = "$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";

        $timestamp = time();
        $nonceStr = $this->createNonceStr();

       // 这里参数的顺序要按照 key 值 ASCII 码升序排序
        $string = "jsapi_ticket=$jsapiTicket&noncestr=$nonceStr&timestamp=$timestamp&url=$url";

        $signature = sha1($string);

        $signPackage = array(
            "appId"     => C('JS_APPID'),
            "nonceStr"  => $nonceStr,
            "timestamp" => $timestamp,
            "url"       => $url,
            "signature" => $signature,
            "rawString" => $string
        );
        return $signPackage; 
    }

    private function createNonceStr($length = 16) {
        $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        $str = "";
        for ($i = 0; $i < $length; $i++) {
            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $str;
    }
    private function getWebAccess($code)
    {
        $appid = C('APPID');
        $secret= C('SECRET');
        $url="https://api.weixin.qq.com/sns/oauth2/access_token?appid=".$appid."&secret=".$secret."&code=".$code."&grant_type=authorization_code";
        $result = json_decode(curl_get_contents($url));
        return $result;
    }

    //getCode模块，网页端获取Code，并进一步获取openid
    private function getCode($redirect_uri, $scope){
        $appid = C('APPID');
        $url="https://open.weixin.qq.com/connect/oauth2/authorize?appid=".$appid."&redirect_uri=".$redirect_uri."&response_type=code&scope=".$scope."#wechat_redirect";
        header("Location:".$url);
        exit;
    }

    private function getAccessToken()
    {
        $time = $this->getTime();
        $accessToken = S('AccessToken');
        if(!empty($accessToken['accessToken'])){
            if($accessToken['expiresTime']>$time){
                return $accessToken['accessToken'];
            }
        }
        $accessToken = $this->getMysqlAccessToken();
        if(!empty($accessToken['accessToken'])){
            if($accessToken['expiresTime']>$time){
                S('AccessToken', $accessToken);
                return $accessToken['accessToken'];
            }
        }
        $accessToken = $this->getNewAccessToken();
        if(!empty($accessToken['accessToken'])){
            $this->setMysqlAccessToken($accessToken);
            S('AccessToken', $accessToken);
            return $accessToken['accessToken'];
        }
        return false;
    }
    
    private function getMysqlAccessToken()
    {
        $tokenModel = M('accessToken');
        $r = $tokenModel->field('accessToken,expiresTime')->order('id desc')->find();
        $result['accessToken']=$r['accesstoken'];
        $result['expiresTime']=$r['expirestime'];
        return $result;
    }

    private function setMysqlAccessToken($accessToken)
    {
        $tokenModel = M('accessToken');
        $tokenModel->create($accessToken);
        $result = $tokenModel->add();
        return $result;
    }

    private function getNewAccessToken()
    {
        $appid = C('JS_APPID');
        $secret= C('JS_SECRET');
        $url="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$appid."&secret=".$secret;
        $result = json_decode(curl_get_contents($url));
        $accessToken = array();
        $accessToken['accessToken'] = $result->access_token;
        $expires_in = $result->expires_in;
        $accessToken['expiresTime'] = $expires_in + time();
        return $accessToken;
    }

    private function getJsApiTicket()
    {
        $time = $this->getTime();
        $jsApiTicket = S('JsApiTicket');
        if(!empty($jsApiTicket)){
            if($jsApiTicket['expiresTime']>$time){
                return $jsApiTicket['jsApiTicket'];
            }
        }
        $jsApiTicket = $this->getMysqlJsApiTicket();
        if(!empty($jsApiTicket['jsApiTicket'])){
            if($jsApiTicket['expiresTime']>$time){
                S('JsApiTicket', $jsApiTicket);
                return $jsApiTicket['jsApiTicket'];
            }
        }
        $jsApiTicket = $this->getNewJsApiTicket();
        $this->setMysqlJsApiTicket($jsApiTicket);
        S('JsApiTicket', $jsApiTicket);
        return $jsApiTicket['jsApiTicket'];
    }
    
    private function getMysqlJsApiTicket()
    {
        $tokenModel = M('jsApiTicket');
        $r = $tokenModel->field('jsApiTicket,expiresTime')->order('id desc')->find();
        $result['jsApiTicket']=$r['jsapiticket'];
        $result['expiresTime']=$r['expirestime'];
        return $result;
    }

    private function setMysqlJsApiTicket($jsApiTicket)
    {
        $tokenModel = M('jsApiTicket');
        $tokenModel->create($jsApiTicket);
        $result = $tokenModel->add();
        return $result;
    }

    private function getNewJsApiTicket()
    {
        $accessToken = $this->getAccessToken();
        $url="https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=".$accessToken."&type=jsapi";
        $result = json_decode(curl_get_contents($url));
        $jsApiTicket = array();
        $jsApiTicket['jsApiTicket'] = $result->ticket;
        $expires_in = $result->expires_in;
        $jsApiTicket['expiresTime'] = $expires_in + time();
        return $jsApiTicket;
    }

    //curl_get_contents方法，用于替代file_get_content
    //$url:目标地址
    //$postData：可选，通过post传递的内容
    private function curlGetContents($url,$postData=null)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_TIMEOUT, 5);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        if ($postData) {
        　　curl_setopt($ch, CURLOPT_POST, 1);
        　　curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
        }
        $r = curl_exec($ch);
        curl_close($ch);
        return $r;
    }
    private function getTime()
    {
        if($this->time){
            return $this->time;
        }
        $time = time()+rand(0,30);
        $this->time = $time;
        return $time;
    }
}
